// Ouzel by Elviss Strazdins

#ifndef OUZEL_INPUT_KEYBOARD_HPP
#define OUZEL_INPUT_KEYBOARD_HPP

#include <bitset>
#include <cstdint>
#include "Controller.hpp"

namespace ouzel::input
{
    class InputManager;

    class Keyboard final: public Controller
    {
        friend InputManager;
    public:
        enum class Key
        {
            none,
            cancel, // Control-break processing
            backspace, // Backspace key
            tab, // Tab key
            clear, // Clear key
            enter, // Enter key
            pause, // Pause key
            capsLock, // Caps Lock key
            kana, // Japanese kana key
            hanja, // Japanese Hanja key
            kanji, // Japanese Kanji key
            yen, // Japanese Yen key
            ro, // Japanese Ro key
            katakana, // Japanese Katakana key
            hiragana, // Japanese Hiragana key
            katakanaHiragana, // Japanese Katakana / Hiragana key
            henkan, // Japanese Henkan key
            muhenkan, // Japanese non-conversion key
            numpadJpcomma, // Japanese numeric keypad comma key
            escape, // Esc key
            space, // Spacebar
            pageUp, // Page Up key
            pageDown, // Page Down key
            end, // End key
            home, // Home key
            left, // Left Arrow key
            up, // Up Arrow key
            right, // Right Arrow key
            down, // Down Arrow key
            select, // Select key
            print, // Print key
            execute, // Execute key
            printScreen, // Print Screen key
            insert, // Ins key
            del, // Delete key
            equal, // Equal key
            help, // Help key
            num0, // 0 key
            num1, // 1 key
            num2, // 2 key
            num3, // 3 key
            num4, // 4 key
            num5, // 5 key
            num6, // 6 key
            num7, // 7 key
            num8, // 8 key
            num9, // 9 key
            a, // A key
            b, // B key
            c, // C key
            d, // D key
            e, // E key
            f, // F key
            g, // G key
            h, // H key
            i, // I key
            j, // J key
            k, // K key
            l, // L key
            m, // M key
            n, // N key
            o, // O key
            p, // P key
            q, // Q key
            r, // R key
            s, // S key
            t, // T key
            u, // U key
            v, // V key
            w, // W key
            x, // X key
            y, // Y key
            z, // Z key
            leftSuper, // Left Windows key (Microsoft Natural keyboard) on Windows, left Command key on macOs
            rightSuper, // Right Windows key (Natural keyboard) on Windows, right Command key on macOs
            menu, // Applications key (Natural keyboard)
            sleep, // Computer sleep key
            power, // Computer power key
            wake,  // Computer wake key
            numpad0, // Numeric keypad 0 key
            numpad1, // Numeric keypad 1 key
            numpad2, // Numeric keypad 2 key
            numpad3, // Numeric keypad 3 key
            numpad4, // Numeric keypad 4 key
            numpad5, // Numeric keypad 5 key
            numpad6, // Numeric keypad 6 key
            numpad7, // Numeric keypad 7 key
            numpad8, // Numeric keypad 8 key
            numpad9, // Numeric keypad 9 key
            numpadMultiply, // Numeric keypad multiply key
            numpadPlus, // Numeric keypad plus key
            numpadSeparator, // Numeric keypad comma key
            numpadMinus, // Numeric keypad minus key
            numpadDecimal, // Numeric keypad decimal key
            numpadDivide, // Numeric keypad divide key
            numpadEnter, // Numeric keypad enter key
            numpadEqual, // Numeric keypad equal key
            numpadPlusminus, // Numeric keypad plus/minus key
            numpadLeftParen, // Numeric keypad comma key
            numpadRightParen, // Numeric keypad comma key
            f1, // F1 key
            f2, // F2 key
            f3, // F3 key
            f4, // F4 key
            f5, // F5 key
            f6, // F6 key
            f7, // F7 key
            f8, // F8 key
            f9, // F9 key
            f10, // F10 key
            f11, // F11 key
            f12, // F12 key
            f13, // F13 key
            f14, // F14 key
            f15, // F15 key
            f16, // F16 key
            f17, // F17 key
            f18, // F18 key
            f19, // F19 key
            f20, // F20 key
            f21, // F21 key
            f22, // F22 key
            f23, // F23 key
            f24, // F24 key
            numLock, // Num Lock key
            scrollLock, // Scroll Lock key
            leftShift, // Left Shift key
            rightShift, // Right Shift key
            leftControl, // Left Control key
            rightControl, // Right Control key
            leftAlt, // Left alt key
            rightAlt, // Right alt key
            modeChange, // Mode change key
            semicolon, // for US ";:"
            plus, // Plus Key "+"
            comma, // Comma Key ","
            minus, // Minus Key "-"
            period, // Period Key "."
            slash, // for US "/?"
            grave, // for US "`~"
            leftBracket, // for US "[{"
            backslash, // for US "\|"
            rightBracket, // for US "]}"
            quote, // for US "'""
            oemAx, // for Japan "AX"
            intlBackslash, // "<>" or "\|"
            crsel, // CrSel key
            exsel, // ExSel key
            app1, // Launch application 1 key
            app2, // Launch application 2 key
            back, // AC back key
            forward, // AC forward key
            refresh, // AC refresh key
            stop, // AC stop key
            search, // AC search key
            bookmarks, // AC bookmarks key
            homepage, // AC home key
            mute, // Audio mute button
            volumeDown, // Audio volume down button
            volumeUp, // Audio volume up button
            audioPlay, // Play/pause media key
            audioStop, // Stop media key
            audioNext, // Play next media key
            audioPrevious, // Play previous media key
            mediaSelect, // Launch media select key
            mail, // Mail function key
            last = mail
        };

        Keyboard(InputManager& initInputManager, DeviceId initDeviceId);

        auto isKeyDown(Key key) const noexcept { return keyStates.test(static_cast<std::size_t>(key)); }

    private:
        bool handleKeyPress(Keyboard::Key key);
        bool handleKeyRelease(Keyboard::Key key);

        std::bitset<static_cast<std::size_t>(Key::last) + 1U> keyStates;
    };
}

#endif // OUZEL_INPUT_KEYBOARD_HPP
